/**
 * @file av_capture.c
 * @author your name (you@domain.com)
 * @brief 启动就不断读取获取音频，图像，并存入固定文件中， 
 * @version 0.1
 * @date 2022-07-29
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include <stdio.h>
#include <string.h>

#include "ak_common.h"
#include "ak_log.h"
#include "ak_ai.h"
#include "ak_vi.h"

#define PCM_FILE_PATH  "/mnt/Audio_Capture/AudioStream.pcm"

#define SAMPLE_RATE 16000
#define AUDIO_CHANNEL_NUM   1
#define DEVICE_ID   DEV_ADC
#define BUFFER_NUM 1024

/******************Video Define********************/
#define VIDEO_CHANNEL_NUM   VIDEO_CHN0
#define VIDEO_DEV_ID    0
#define DMA_ENABLE  0
#define VIDEO_HEIGHT    480
#define VIDEO_WIDTH     640
// #define 
// #define DMA_ENABLE  1    TODO 
#define DEF_FRAME_DEPTH     3
#define ISP_PATH "isp_pr2000_dvp_pal_25fps_27M.conf"
#define VIDEO_FILE_PATH  "/mnt/Video_Capture/VideoStream.yuv"

/*******************Function Declare***************/
static int start_vi(int dev_id);
static int vi_capture_loop(int number, VI_CHN_ATTR *attr_sub);

static VI_CHN_ATTR chn_attr = {0};
static VI_CHN_ATTR chn_attr_sub = {0};

int FrameCount = 0;

int main(int argc, char **argv)
{
    /* start the application */
    int ret = -1;
    sdk_run_config config = {0};
    config.mem_trace_flag = SDK_RUN_NORMAL;
    ak_sdk_init( &config );

    /* open file */
    FILE *pcm_fp;
    
    struct ak_audio_in_param param;
    memset(&param, 0, sizeof(struct ak_audio_in_param));
    param.pcm_data_attr.sample_rate = SAMPLE_RATE;                // set sample rate
    param.pcm_data_attr.sample_bits = AK_AUDIO_SMPLE_BIT_16;    // sample bits only support 16 bit
    param.pcm_data_attr.channel_num = AUDIO_CHANNEL_NUM;    // channel number
    param.dev_id = DEVICE_ID;//DEV_ADC;

    int ai_handle_id = -1;
    if (ak_ai_open(&param, &ai_handle_id))
    {
        ak_print_normal(MODULE_ID_APP, "*** ak_ai_open failed. ***\n");
        return -1;
    }
    // ret = ak_vi_open(VIDEO_DEV0);

    /* 打开文件在后面补充，没有文件就新建 */
    pcm_fp = fopen(PCM_FILE_PATH, "wb");
    if (NULL == pcm_fp)
    {
        perror("open pcm");
        return -1;
    }
        
    ret = ak_ai_set_source(ai_handle_id, AI_SOURCE_MIC);
    ret = ak_ai_set_gain(ai_handle_id, 5);    
    struct ak_audio_nr_attr     default_ai_nr_attr      = {-40, 0, 1};
    ret = ak_ai_set_nr_attr(ai_handle_id, &default_ai_nr_attr);
    struct ak_audio_agc_attr    default_ai_agc_attr     = {24576, 4, 0, 80, 0, 1};
    ret = ak_ai_set_agc_attr(ai_handle_id, &default_ai_agc_attr);
    ret = ak_ai_set_volume(ai_handle_id, 5);

    ret = ak_ai_start_capture(ai_handle_id);
    if (ret)
    {
        ak_print_error(MODULE_ID_APP, "*** ak_ai_start_capture failed. ***\n");
        ak_ai_close(ai_handle_id);
        fclose(pcm_fp);
        return -1;
    }

    /*vi config*/
    ret = -1;
    /*
     * step 1: start vi
     */
    ret = start_vi(VIDEO_DEV_ID);
    if (ret)
    {
        return -1;
    }

    unsigned long long enter_ts = 0;
    struct frame ai_frame = {0};
    while(1)
    {
        int ret = -1;

        ret = ak_ai_get_frame(ai_handle_id, &ai_frame, 0);
        if(ret)
        {
            if (ERROR_AI_NO_DATA == ret)
            {
                continue;
            }
            else
            {
                ak_sleep_ms(10);
                ak_print_normal(MODULE_ID_APP, "get ai_frame fail!\n");
                return -1;
            }
        }

        if (!ai_frame.data || ai_frame.len <= 0)
        {
            ak_print_normal(MODULE_ID_APP, "frame data null \n");
            ak_sleep_ms(10);
            continue;
        }

        if(fwrite(ai_frame.data, ai_frame.len, 1, pcm_fp) < 0)
        {
            ak_print_normal(MODULE_ID_APP, "write file error.\n");
            break;
        }
        FrameCount ++;
        printf("%d\n", ai_frame.len);
        /* 打开文件后加入互斥锁TODO */

        if(enter_ts == 0)
        {
            enter_ts = ai_frame.ts;
        }
        unsigned long long now_ts = ai_frame.ts;

        if(now_ts - enter_ts > 10000)
        {
            break;
        }
        ak_ai_release_frame(ai_handle_id, &ai_frame);

    }

    if(fclose(pcm_fp) < 0)
    {
        perror("close pcm");
        return -1;
    }  
   
    ret = ak_ai_stop_capture(ai_handle_id);
    if (ret)
    {
        ak_print_error(MODULE_ID_APP, "*** ak_ai_stop_capture failed. ***\n");
        ak_ai_close(ai_handle_id);
        return -1;
    }

    ak_ai_close(ai_handle_id);

    vi_capture_loop(10, &chn_attr_sub);

    ak_vi_disable_chn(VIDEO_CHANNEL_NUM);
	ak_vi_disable_dev(VIDEO_DEV_ID);

    // stop_vi(VIDEO_DEV0);
    return 0;
}

static int start_vi(int dev_id)
{
    /*
     * step 0: global value initialize
     */
    int ret = -1;                                //return value
    int width = VIDEO_WIDTH;
    int height = VIDEO_HEIGHT;
    int subwidth = VIDEO_WIDTH;
    int subheight = VIDEO_HEIGHT;
    int chn_main_id = VIDEO_CHN0;
    int chn_sub_id = VIDEO_CHN1;
    int chn_trd_id = VIDEO_CHN16;

    /* open vi flow */

    /*
     * step 1: open video input device
     */
    ret = ak_vi_open(dev_id);
    if (AK_SUCCESS != ret) {
        ak_print_error_ex(MODULE_ID_APP, "vi device %d open failed\n", dev_id);
        return ret;
    }

    /* default vi ae para */
#ifdef AK_RTOS
#ifndef __CHIP_AK37E_SERIES
#include "ak_vpss.h"
    struct vpss_isp_ae_init_info ae_init_info;
    ae_init_info.a_gain = 256;
    ae_init_info.d_gain = 256;
    ae_init_info.exp_time = 2154;
    ae_init_info.isp_d_gain = 256;
    ak_vpss_set_ae_init_info(dev_id, &ae_init_info);
#endif
#endif


#ifndef __CHIP_AK37E_SERIES
    /*
     * step 2: load isp config
     */
    ret = ak_vi_load_sensor_cfg(dev_id, ISP_PATH);
    if (AK_SUCCESS != ret) {
        ak_print_error_ex(MODULE_ID_APP, "vi device %d load isp cfg [%s] failed!\n", dev_id, ISP_PATH);
        return ret;
    }
#endif
    /*
     * step 3: get sensor support max resolution
     */
    RECTANGLE_S res;                //max sensor resolution
    VI_DEV_ATTR    dev_attr;
    memset(&dev_attr, 0, sizeof(VI_DEV_ATTR));
    dev_attr.dev_id = dev_id;
    dev_attr.crop.left = 0;
    dev_attr.crop.top = 0;
    dev_attr.crop.width = width;
    dev_attr.crop.height = height;
    dev_attr.max_width = width;
    dev_attr.max_height = height;
    dev_attr.sub_max_width = subwidth;
    dev_attr.sub_max_height = subheight;

    /* get sensor resolution */
    ret = ak_vi_get_sensor_resolution(dev_id, &res);
    if (ret) {
        ak_print_error_ex(MODULE_ID_APP, "Can't get dev[%d]resolution\n", dev_id);
        ak_vi_close(dev_id);
        return ret;
    } else {
        ak_print_normal_ex(MODULE_ID_APP, "get dev res w:[%d]h:[%d]\n",res.width, res.height);
        dev_attr.crop.width = res.width;
        dev_attr.crop.height = res.height;
    }

    /*
     * step 4: set vi device working parameters
     * default parameters: 25fps, day mode
     */
    ret = ak_vi_set_dev_attr(dev_id, &dev_attr);
    if (ret) {
        ak_print_error_ex(MODULE_ID_APP, "vi device %d set device attribute failed!\n", dev_id);
        ak_vi_close(dev_id);
        return ret;
    }

    /*
     * step 5: set main channel attribute
     */

    memset(&chn_attr, 0, sizeof(VI_CHN_ATTR));
    chn_attr.chn_id = chn_main_id;
    chn_attr.res.width = width;
    chn_attr.res.height = height;
    chn_attr.frame_depth = DEF_FRAME_DEPTH;
    /*disable frame control*/
    chn_attr.frame_rate = 0;
    ret = ak_vi_set_chn_attr(chn_main_id, &chn_attr);
    if (ret) {
        ak_print_error_ex(MODULE_ID_APP, "vi device %d set channel [%d] attribute failed!\n", dev_id, chn_main_id);
        ak_vi_close(dev_id);
        return ret;
    }
    ak_print_normal_ex(MODULE_ID_APP, "vi device %d main sub channel attribute\n", dev_id);

#ifndef __CHIP_AK37E_SERIES
    /*
     * step 6: set sub channel attribute
     */

    memset(&chn_attr_sub, 0, sizeof(VI_CHN_ATTR));
    chn_attr_sub.chn_id = chn_sub_id;
    chn_attr_sub.res.width = subwidth;
    chn_attr_sub.res.height = subheight;
    chn_attr_sub.frame_depth = DEF_FRAME_DEPTH;
    /*disable frame control*/
    chn_attr_sub.frame_rate = 0;
    ret = ak_vi_set_chn_attr(chn_sub_id, &chn_attr_sub);
    if (ret) {
        ak_print_error_ex(MODULE_ID_APP, "vi device %d set channel [%d] attribute failed!\n", dev_id, chn_sub_id);
        ak_vi_close(dev_id);
        return ret;
    }
    ak_print_normal_ex(MODULE_ID_APP, "vi device %d set sub channel attribute\n", dev_id);

#ifdef THIRD_CHN_SUPPORT
    /*
     * step 7: set third channel attribute
     */
    VI_CHN_ATTR chn_attr_td;
    memset(&chn_attr_td, 0, sizeof(VI_CHN_ATTR));
    chn_attr_td.chn_id = chn_trd_id;
	/* resolution of third channel must be half of the resolution of sub channel */
	chn_attr_td.res.width = subwidth/2;
    chn_attr_td.res.height = subheight/2;
    chn_attr_td.frame_depth = DEF_FRAME_DEPTH;
    /*disable frame control*/
    chn_attr_td.frame_rate = 0;
    ret = ak_vi_set_chn_attr(chn_trd_id, &chn_attr_td);
    if (ret) {
        ak_print_error_ex(MODULE_ID_APP, "vi device %d set channel [%d] attribute failed!\n", dev_id, chn_trd_id);
        ak_vi_close(dev_id);
        return ret;
    }
    ak_print_normal_ex(MODULE_ID_APP, "vi device %d set td channel attribute\n", dev_id);
#endif
#endif
	/*
     * step 8: enable vi device
     */
    ret = ak_vi_enable_dev(dev_id);
    if (ret) {
        ak_print_error_ex(MODULE_ID_APP, "vi device %d enable device  failed!\n", dev_id);
        ak_vi_close(dev_id);
        return ret;
    }

    /*
     * step 9: enable vi main channel
     */
    ret = ak_vi_enable_chn(chn_main_id);
    if(ret)
    {
        ak_print_error_ex(MODULE_ID_APP, "vi channel[%d] enable failed!\n", chn_main_id);
        ak_vi_close(dev_id);
        return ret;
    }

#ifndef __CHIP_AK37E_SERIES
    /*
     * step 10: enable vi sub channel
     */
    ret = ak_vi_enable_chn(chn_sub_id);
    if(ret)
    {
        ak_print_error_ex(MODULE_ID_APP, "vi channel[%d] enable failed!\n",chn_sub_id);
        ak_vi_close(dev_id);
        return ret;
    }
#ifdef THIRD_CHN_SUPPORT
    /*
     * step 11: enable vi third channel
     */
    ret = ak_vi_enable_chn(chn_trd_id);
    if(ret)
    {
        ak_print_error_ex(MODULE_ID_APP, "vi channel[%d] enable failed!\n",chn_trd_id);
        ak_vi_close(dev_id);
        return ret;
    }
#endif
#endif
    return 0;
}

static int vi_capture_loop(int number, VI_CHN_ATTR *attr_sub)
{
    int count = 0;
    int chn_id = 0;
    struct video_input_frame frame = {0};

    ak_print_normal(MODULE_ID_APP, "capture start\n");

    /*
     * To get frame by loop
     */
    while (count <  number)
    {
        chn_id = VIDEO_CHANNEL_NUM;

        memset(&frame, 0x00, sizeof(frame));

        /* to get frame according to the channel number */
        int ret = ak_vi_get_frame(chn_id, &frame);

        if (!ret) 
        {
            FILE *fd;
            /*
            * open appointed file to save YUV data
            * save main channel yuv here
            */
            fd = fopen(VIDEO_FILE_PATH, "w+b");
            if (fd) 
            {
                unsigned char *buf = frame.vi_frame.data;
                unsigned int   len = frame.vi_frame.len;
                ret = fwrite(buf, 1, len, fd);
                if(ret < len)
                {
                    ak_print_error(MODULE_ID_APP, "write yuv file failed!!\n");
                    fclose(fd);
                    return -1;
                }

                fclose(fd);
            } 
            else 
            {
                ak_print_normal(MODULE_ID_APP, "open YUV file[%s] failed!!\n", VIDEO_FILE_PATH);
            }
            /*
                * in this context, this frame was useless,
                * release frame data
                */
            ak_vi_release_frame(chn_id, &frame);
            count++;

        } 
        else 
        {

            /*
                *    If getting too fast, it will have no data,
                *    just take breath.
                */
            ak_print_normal_ex(MODULE_ID_APP, "get frame failed!\n");
            ak_sleep_ms(10);
        }

    }

    ak_print_normal(MODULE_ID_APP,"capture finish\n\n");
    
    return 0;
}